package android.contest.weather;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;

import android.content.Context;
import android.contest.util.Log;

public class Weather {

	/* Our Handler now provides the parsed weather-data to us. */
	private static WeatherSet ws = null;
	private static final String WEATHER_XML = "weather.xml";
	private static final int CLEAR_EX = 1;
	private static final int CLOUDY_ABOVE = 2; 
	
	private static WeatherSet getWeatherSet() {
		if (ws == null) {
			Log.d(Log.LOGWEATHER, "Haha , this is a DEBUG of MyAndroid. ");
			URL url;
			try {
				String cityParamString = "Shanghai";
				String queryString = "http://www.google.com/ig/api?weather="
						+ cityParamString + "&hl=en-us";
				/* Replace blanks with HTML-Equivalent. */
				url = new URL(queryString.replace(" ", "%20"));

				/* Get a SAXParser from the SAXPArserFactory. */
				SAXParserFactory spf = SAXParserFactory.newInstance();
				SAXParser sp = spf.newSAXParser();

				/* Get the XMLReader of the SAXParser we created. */
				XMLReader xr = sp.getXMLReader();

				/*
				 * Create a new ContentHandler and apply it to the XML-Reader
				 */
				GoogleWeatherHandler gwh = new GoogleWeatherHandler();
				xr.setContentHandler(gwh);

				/* Parse the xml-data our URL-call returned. */
				xr.parse(new InputSource(url.openStream()));

				/* Our Handler now provides the parsed weather-data to us. */
				ws = gwh.getWeatherSet();

				Log.d(Log.LOGWEATHER, "==================================");
				Log.d(Log.LOGWEATHER, "Current Condition: "
						+ ws.getWeatherCurrentCondition().getCondition());
				Log.d(Log.LOGWEATHER, "Tempurature: "
						+ ws.getWeatherCurrentCondition().getTempCelcius()
								.toString() + "'C");
				Log.d(Log.LOGWEATHER, ws.getWeatherCurrentCondition()
						.getWindCondition());
				Log.d(Log.LOGWEATHER, ws.getWeatherCurrentCondition()
						.getHumidity());
				Log.d(Log.LOGWEATHER, "==================================");
				Log.d(Log.LOGWEATHER, ws.getWeatherForecastConditions().get(0)
						.getDayofWeek());
				Log.d(Log.LOGWEATHER, "Forecast Condition: "
						+ ws.getWeatherForecastConditions().get(0)
								.getCondition());
				Log.d(Log.LOGWEATHER, "Tempurature: "
						+ ws.getWeatherForecastConditions().get(0)
								.getTempMinCelsius().toString()
						+ "'C"
						+ " to "
						+ ws.getWeatherForecastConditions().get(0)
								.getTempMaxCelsius().toString() + "'C");

			} catch (Exception e) {
				Log.e(Log.LOGWEATHER, "WeatherQueryError", e);
			}
		}
		return ws;

	}

	public static boolean SatisfyCondition(Context context, int level) {
		String forecastedCondition = "<>";
		try {
//			ws = getWeatherSet();
			ws = Weather.readWeatherSet(context);
			if(ws == null){ // if it cannot get weather information from either from the Internet or the local file, always allow
				return true;
			}
			forecastedCondition = ws.getWeatherForecastConditions().get(0)
					.getCondition();
		} catch (Exception e) {
			Log.e(Log.LOGWEATHER, "WeatherQueryError", e);
		}
		Log.v(Log.LOGWEATHER, "forecastCondition = " + forecastedCondition);
		Log.v(Log.LOGWEATHER,
				"forecastCondition is "
						+ (forecastedCondition.equalsIgnoreCase("clear")
								|| forecastedCondition
										.equalsIgnoreCase("partly_cloudy")/* || forecastedCondition
									.equalsIgnoreCase(forecastedCondition)*/));

		// all fine weathers: <Clear>, <Mostly Sunny>, <Chance of Rain>, <Partly Cloudy>
		// return forecastedCondition.equalsIgnoreCase("clear")
		// ||forecastedCondition.equalsIgnoreCase("partly_cloudy");
		switch(level){
		case CLEAR_EX:
			return forecastedCondition.equalsIgnoreCase("clear");
		case CLOUDY_ABOVE:
			return forecastedCondition.equalsIgnoreCase("Clear")
					|| forecastedCondition.equalsIgnoreCase("Partly Cloudy")
					|| forecastedCondition.equalsIgnoreCase("Partly Sunny")
					|| forecastedCondition.equalsIgnoreCase("Mostly Sunny");
			default:
				throw new java.lang.Error("Unknown weather condition level!!");
		}

		// always return true for testing
		// return true;
	}

	public static String TmrwCond() {
		String forecastedCondition = "<empty>";
		try {
			ws = getWeatherSet();
			forecastedCondition = ws.getWeatherForecastConditions().get(0)
					.getCondition();
		} catch (Exception e) {
			Log.e(Log.LOGWEATHER, "WeatherQueryError", e);
		}
		// Log.v(Log.LOGWEATHER, "forecastCondition = " + forecastedCondition);
		// Log.v(Log.LOGWEATHER, "forecastCondition is " +
		// (forecastedCondition.equalsIgnoreCase("clear")
		// ||forecastedCondition.equalsIgnoreCase("partly_cloudy")
		// ||forecastedCondition.equalsIgnoreCase(forecastedCondition)));

		return forecastedCondition;
	}

	public static boolean saveWeatherFile(Context context) {
		Log.d(Log.LOGWEATHER, "Weather.saveWeatherFile():");
		boolean rv;
		URL url;
		try{
			String cityParamString = "Shanghai";
			String queryString = "http://www.google.com/ig/api?weather="
					+ cityParamString + "&hl=en-us";
			/* Replace blanks with HTML-Equivalent. */
			url = new URL(queryString.replace(" ", "%20"));

			byte[]ss = new byte[4096]; 
			InputStream is = url.openStream();
			int bytecnt = is.read(ss);
			FileOutputStream fos = context.openFileOutput(Weather.WEATHER_XML, Context.MODE_PRIVATE); 
			fos.write(ss, 0, bytecnt);
			fos.flush();
			fos.close();
			rv = true;
		}catch(Exception e){
			Log.e(Log.LOGWEATHER, "WeatherQueryError", e);
			e.printStackTrace();
			rv = false;
		}
		
		return rv;
	}

	/**
	 * 
	 * @return, the valid weatherset. null if the stored xml is obsolete and no access to the internet for updated one
	 */
	public static WeatherSet readWeatherSet(Context context) {
		// read from Internet first. if success, save the file
		// if failure, read from the local xml file
		// if local xml is obsolete, return null
		Log.d(Log.LOGWEATHER, "Weather.readWeatherSet(): begins ");
		String cityParamString = "Shanghai";
		String queryString = "http://www.google.com/ig/api?weather="
				+ cityParamString;
		/* Replace blanks with HTML-Equivalent. */
		URL url = null;
		try {
			url = new URL(queryString.replace(" ", "%20"));
		} catch (MalformedURLException e1) {
			e1.printStackTrace();
			return null;
		}
		InputStream is = null;
		boolean readFromInternet = false;
		try {

			/* Get a SAXParser from the SAXPArserFactory. */
			SAXParserFactory spf = SAXParserFactory.newInstance();
			SAXParser sp = spf.newSAXParser();

			/* Get the XMLReader of the SAXParser we created. */
			XMLReader xr = sp.getXMLReader();

			/*
			 * Create a new ContentHandler and apply it to the XML-Reader
			 */
			GoogleWeatherHandler gwh = new GoogleWeatherHandler();
			xr.setContentHandler(gwh);

			/* Parse the xml-data our URL-call returned. */
			is = url.openStream();
			xr.parse(new InputSource(is));

			/* Our Handler now provides the parsed weather-data to us. */
			ws = gwh.getWeatherSet();
			readFromInternet = true;
			is.close();
			Log.v(Log.LOGWEATHER, "Weather.readWeatherSet(): read from the internet successfully!");

		} catch (Exception e) {
			readFromInternet = true;
			Log.e(Log.LOGWEATHER, "Weather.readWeatherSet(): read from the internet failure!!", e);
			e.printStackTrace();
		}
		
		if (readFromInternet) {
			try {
				byte[] ss = new byte[4096];
				int bytecnt;
				is = url.openStream();
				bytecnt = is.read(ss);
				is.close();
				FileOutputStream fos = context.openFileOutput(
						Weather.WEATHER_XML, Context.MODE_PRIVATE);
				fos.write(ss, 0, bytecnt);
				fos.flush();
				fos.close();
				Log.v(Log.LOGWEATHER, "Weather.readWeatherSet(): save to the local xml file successfully!");
				return ws;
			} catch (IOException e) {
				// TODO Auto-generated catch block
				Log.e(Log.LOGWEATHER, "Weather.readWeatherSet(): save to the local xml file failure!", e);
				e.printStackTrace();
			}
		} else {
			try {
				FileInputStream fis = context.openFileInput(WEATHER_XML);
				/* Get a SAXParser from the SAXPArserFactory. */
				SAXParserFactory spf = SAXParserFactory.newInstance();
				SAXParser sp = spf.newSAXParser();

				/* Get the XMLReader of the SAXParser we created. */
				XMLReader xr = sp.getXMLReader();
				/*
				 * Create a new ContentHandler and apply it to the XML-Reader
				 */
				GoogleWeatherHandler gwh = new GoogleWeatherHandler();
				xr.setContentHandler(gwh);

				/* Parse the xml-data our URL-call returned. */
				xr.parse(new InputSource(fis));
				
				/* Our Handler now provides the parsed weather-data to us. */
				ws = gwh.getWeatherSet();
				SimpleDateFormat sdf =   new SimpleDateFormat("yyyy-MM-dd");
				Date forecast_date = sdf.parse(ws.getCurrentDateTime()) ;

				Calendar c_now = Calendar.getInstance();
				c_now.setTimeInMillis(System.currentTimeMillis());
				Date now = new Date(c_now.get(Calendar.YEAR), c_now.get(Calendar.MONTH), c_now.get(Calendar.DATE));
				
				Log.v(Log.LOGWEATHER, "Weather.readWeatherSet(): read from local xml file, c_now="+c_now.getTime().toString() );
				Log.v(Log.LOGWEATHER, "Weather.readWeatherSet(): read from local xml file, now="+now.toString() );
				Log.v(Log.LOGWEATHER, "Weather.readWeatherSet(): read from local xml file, forecast_date="+forecast_date.toString() );
				
				fis.close();

				if(forecast_date.before(now)){
					return null;
				}else{
					return ws;
				}
				
				
			} catch (FileNotFoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (SAXException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (ParserConfigurationException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (ParseException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		return null;  // if read from local file failure
	}
}
